﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;

using NAudio.Midi;

using Microsoft.DirectX.AudioVideoPlayback;

namespace MIDIDrum
{
    public partial class MainForm : Form
    {
        MidiEventCollection events = new MidiEventCollection(1, 512);
        DateTime regStart;
        public MidiIn midiIn;
        string fileOut;

        #region Sounds
        Audio[] audios = new Audio[128];
        private void LoadSounds()
        {
            Nini.Ini.IniDocument doc = new Nini.Ini.IniDocument("settings.ini");
            Nini.Ini.IniSection sect = doc.Sections["SOUNDS"];
            for (int i = 0; i < sect.ItemCount; i++)
            {
                Nini.Ini.IniItem item = sect.GetItem(i);
                if (!item.Name.StartsWith("#comment"))
                    audios[int.Parse(item.Name)] = new Audio("drumset/" + item.Value);
            }
        }
        #endregion

        public MainForm()
        {
            InitializeComponent();
            LoadSounds();
        }

        #region Functions
        public void StartMonitoring(int MIDIInDevice)
        {
            if (btnStart.Text == "Start")
            {
                if (midiIn == null)
                {
                    midiIn = new MidiIn(MIDIInDevice);
                }
                midiIn.Start();
                btnStart.Text = "Stop";
                btnSettings.Enabled = false;
            }
            else
            {
                midiIn.Stop();
                midiIn.Dispose();
                midiIn = null;
                btnStart.Text = "Start";
                if (fileOut != null)
                {
                    AppendEndMarker(events[0]);
                    MidiFile.Export(fileOut, events);
                    chkRegister.Checked = false;
                }
                btnSettings.Enabled = true;
            }
        }

        public string[] GetMIDIInDevices()
        {
            // Get a list of devices 
            string[] returnDevices = new string[MidiIn.NumberOfDevices];

            // Get the product name for each device found 
            for (int device = 0; device < MidiIn.NumberOfDevices; device++)
            {
                returnDevices[device] = MidiIn.DeviceInfo(device).ProductName;
            }
            return returnDevices;
        }

        private void AppendEndMarker(IList<MidiEvent> eventList)
        {
            long absoluteTime = 0;
            if (eventList.Count > 0)
                absoluteTime = eventList[eventList.Count - 1].AbsoluteTime;
            eventList.Add(new MetaEvent(MetaEventType.EndTrack, 0, absoluteTime));
        }
        #endregion

        private void btnRefresh_Click(object sender, EventArgs e)
        {
            cmbInputs.Items.Clear();
            foreach (string str in GetMIDIInDevices())
            {
                cmbInputs.Items.Add(str);
            }
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            foreach (string str in GetMIDIInDevices())
            {
                cmbInputs.Items.Add(str);
            }
            try
            {
                cmbInputs.SelectedIndex = 0;
            }
            catch (Exception)
            {
                System.Windows.Forms.MessageBox.Show("No MIDI Device Detected");
            }
            events.AddTrack();
            //events[0].Add(new NAudio.Midi.PatchChangeEvent(0, 1, 10));
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            StartMonitoring(cmbInputs.SelectedIndex);
            if (btnStart.Text == "Stop")
                midiIn.MessageReceived += new EventHandler<MidiInMessageEventArgs>(midiIn_MessageReceived);
        }

        private void midiIn_MessageReceived(object sender, MidiInMessageEventArgs e)
        {
            if (e.MidiEvent != null && e.MidiEvent.CommandCode == MidiCommandCode.AutoSensing)
            {
                return;
            }
            if (e.MidiEvent.CommandCode == MidiCommandCode.NoteOn)
            {
                NoteOnEvent ne;
                ne = (NoteOnEvent)e.MidiEvent;
                if (chkRegister.Checked)
                {
                    long millis = (long)(DateTime.Now - regStart).TotalMilliseconds;
                    NoteOnEvent evt = new NoteOnEvent(millis, 10, ne.NoteNumber, ne.Velocity, ne.NoteLength);
                    events[0].Add(evt);
                    NoteOnEvent off = new NoteOnEvent(millis + ne.NoteLength, 10, ne.NoteNumber, 0, 0);
                    events[0].Add(off);
                }
                /*int volume = (int)((float)ne.Velocity * (1000.0f / 127.0f) - 1000);
                bass.Volume = volume;
                red.Volume = volume;
                blue.Volume = volume;
                green.Volume = volume;
                yellow.Volume = volume;
                orange.Volume = volume;*/
                int a = 3;
                /*switch (ne.NoteNumber)
                {
                    case 36:
                        bass.CurrentPosition = 0;
                        bass.Play();
                        break;
                    case 38:
                        red.CurrentPosition = 0;
                        red.Play();
                        break;
                    case 41:
                        blue.CurrentPosition = 0;
                        blue.Play();
                        break;
                    case 42:
                        yellow.CurrentPosition = 0;
                        yellow.Play();
                        break;
                    case 53:
                        green.CurrentPosition = 0;
                        green.Play();
                        break;
                    case 55:
                        orange.CurrentPosition = 0;
                        orange.Play();
                        break;
                }*/
                if (audios[ne.NoteNumber] != null)
                {
                    Audio audio = audios[ne.NoteNumber];
                    audio.Volume = (int)((float)ne.Velocity * (1000.0f / 127.0f) - 1000);
                    audio.CurrentPosition = 0;
                    audio.Play();
                }
            }
        }

        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (midiIn != null)
                midiIn.Dispose();

            if (fileOut != null)
            {
                AppendEndMarker(events[0]);
                MidiFile.Export(fileOut, events);
            }
        }

        private void chkRegister_CheckedChanged(object sender, EventArgs e)
        {
            if (chkRegister.Checked)
            {
                SaveFileDialog dial = new SaveFileDialog();
                dial.Title = "Select output file";
                dial.Filter = "MIDI File|*.mid";
                if (dial.ShowDialog() == DialogResult.OK)
                {
                    fileOut = dial.FileName;
                    regStart = DateTime.Now;
                }
                else
                {
                    chkRegister.Checked = false;
                }
            }
        }

        #region Help icon
        private void pctInfo_MouseHover(object sender, EventArgs e)
        {
            pctInfo.BackgroundImage = MIDIDrum.Properties.Resources.information;
            while (pctInfo.Width < 32)
            {
                pctInfo.Width++;
                pctInfo.Height++;
                Application.DoEvents();
                System.Threading.Thread.Sleep(10);
            }
        }

        private void pctInfo_MouseLeave(object sender, EventArgs e)
        {
            while (pctInfo.Width > 16)
            {
                pctInfo.Width--;
                pctInfo.Height--;
                Application.DoEvents();
                System.Threading.Thread.Sleep(10);
            }
            pctInfo.BackgroundImage = MIDIDrum.Properties.Resources.information_16;
        }

        private void pctInfo_Click(object sender, EventArgs e)
        {
            System.Diagnostics.Process.Start("http://mididrum.codeplex.com");
        }
        #endregion

        private void btnSettings_Click(object sender, EventArgs e)
        {
            SettingsForm form = new SettingsForm();
            form.FormClosed += delegate(object sndr, FormClosedEventArgs fcea)
            {
                LoadSounds();
            };
            form.ShowDialog();
        }
    }
}
